import json
import os
import re
import uuid
from typing import List, Dict, Any, Optional, Tuple
from pathlib import Path

# 添加项目根目录到sys.path
import sys
PROJECT_ROOT = Path(__file__).parent.parent.parent
sys.path.append(str(PROJECT_ROOT))

from langchain_core.documents import Document
from langchain_core.embeddings import Embeddings

# 使用正确的相对导入路径
from ..core.logger import logger
from ..core.config import settings
from .vector_store_factory import VectorStoreFactory
from .hybrid_search import HybridSearchEngine


class VectorStore:
    def __init__(self, embedding_provider: Any):
        self.embedding = embedding_provider.get_embedding()
        logger.info(
            f"VectorStore initialized with embedding provider: "
            f"{type(embedding_provider).__name__}"
        )
        
        # 使用工厂模式创建向量数据库实例
        self.vector_store = VectorStoreFactory.create_vector_store(embedding_provider)
        
        vector_store_type = type(self.vector_store).__name__
        logger.info(f"Vector store initialized: {vector_store_type}")
        
        # 添加更多关于向量存储的信息
        logger.info(f"Vector store type info: {str(type(self.vector_store)).lower()}")
        
        # 检查是否支持过滤功能
        supports_filter = (
            hasattr(self.vector_store, '_filter') or 
            'milvus' in str(type(self.vector_store)).lower() or
            'chroma' in str(type(self.vector_store)).lower()
        )
        logger.info(f"Vector store supports filter: {supports_filter}")

    def add_documents(self, documents: List[Document]):
        logger.info(f"Adding {len(documents)} documents to vector store")
        try:
            # 为每个文档添加唯一的id字段并检查元数据
            documents_with_id = []
            metadata_status = {}  # 初始化metadata_status字典
            
            for i, doc in enumerate(documents):
                # 确保文档有metadata属性
                if not hasattr(doc, 'metadata'):
                    doc.metadata = {}
                    
                # 检查文档是否已经有id
                if 'id' not in doc.metadata:
                    # 添加唯一的id
                    doc.metadata['id'] = str(uuid.uuid4())
                
                # 检查关键元数据字段是否存在，如果不存在则添加
                if 'source' not in doc.metadata and 'file_path' in doc.metadata:
                    doc.metadata['source'] = doc.metadata['file_path']
                if 'file_name' not in doc.metadata and 'source' in doc.metadata:
                    doc.metadata['file_name'] = os.path.basename(doc.metadata['source'])
                if 'file_type' not in doc.metadata:
                    # 从文件名推断文件类型
                    if 'file_name' in doc.metadata:
                        _, ext = os.path.splitext(doc.metadata['file_name'])
                        doc.metadata['file_type'] = ext[1:].lower() if ext else 'unknown'
                    else:
                        doc.metadata['file_type'] = 'unknown'
                
                # 统计元数据状态
                if i < 3:  # 只记录前3个文档的详细元数据信息
                    metadata_status[f"doc_{i+1}"] = {
                        'has_source': 'source' in doc.metadata,
                        'has_filename': 'file_name' in doc.metadata,
                        'has_company_name': 'company_name' in doc.metadata,
                        'has_business_type': 'business_type' in doc.metadata,
                        'has_total_pages': 'total_pages' in doc.metadata,
                        'has_filetype': 'file_type' in doc.metadata,
                        'source': doc.metadata.get('source', 'N/A'),
                        'file_name': doc.metadata.get('file_name', 'N/A'),
                        'company_name': doc.metadata.get('company_name', 'N/A'),
                        'business_type': doc.metadata.get('business_type', 'unknown'),
                        'total_pages': doc.metadata.get('total_pages', 'N/A'),
                        'file_type': doc.metadata.get('file_type', 'N/A')
                    }
                
                documents_with_id.append(doc)
            
            # 记录前几个文档的元数据状态
            if metadata_status:
                logger.info(f"前3个文档的元数据状态: {json.dumps(metadata_status, ensure_ascii=False, indent=2)}")
            
            try:
                # 尝试添加文档到向量数据库
                self.vector_store.add_documents(documents_with_id)
                logger.info(f"Documents successfully added to vector store, total: {len(documents_with_id)}")
            except Exception as e:
                # 捕获Milvus向量缺失错误
                if "Insert missed an field `vector`" in str(e):
                    logger.error(f"Milvus向量缺失错误: {e}")
                    # 测试嵌入提供者状态
                    try:
                        test_vector = self.embedding.embed_query("test")
                        logger.info(f"嵌入提供者测试结果: 向量长度={len(test_vector)}，向量示例={test_vector[:3]}...")
                        
                        # 如果测试向量有效，重新尝试添加
                        if test_vector and len(test_vector) > 0:
                            logger.info("嵌入提供者功能正常，尝试重新添加文档...")
                            # 为了安全起见，我们尝试只添加第一个文档
                            if len(documents_with_id) > 0:
                                try:
                                    self.vector_store.add_documents([documents_with_id[0]])
                                    logger.info("成功添加单个文档，问题可能与批量大小有关")
                                    # 记录成功，允许程序继续运行
                                    return
                                except Exception as retry_e:
                                    logger.error(f"重新尝试添加失败: {retry_e}")
                    except Exception as test_e:
                        logger.error(f"嵌入提供者测试失败: {test_e}")
                    
                    # 根据当前配置的嵌入类型生成更动态的错误消息
                    check_points = ["1. 嵌入模型配置是否正确"]
                    
                    if settings.EMBEDDING_TYPE == 'custom':
                        check_points.append("2. 自定义嵌入服务是否可用")
                        check_points.append(f"3. 嵌入模型 '{settings.EMBEDDING_MODEL}' 是否在自定义服务中正确部署")
                        check_points.append("4. 服务是否能够生成有效的向量数据")
                    elif settings.EMBEDDING_TYPE == 'ollama':
                        check_points.append(f"2. Ollama服务是否正常运行: {settings.OLLAMA_BASE_URL}")
                        check_points.append(f"3. Ollama嵌入模型 '{settings.OLLAMA_EMBEDDING_MODEL}' 是否正确下载和配置")
                        check_points.append("4. Ollama服务是否能够生成有效的向量数据")
                        check_points.append("5. 确保EMBEDDING_TYPE设置为'ollama'而非'custom'")
                    elif settings.EMBEDDING_TYPE == 'huggingface':
                        check_points.append(f"2. Hugging Face模型 '{settings.EMBEDDING_MODEL}' 是否正确下载")
                        check_points.append("3. 系统资源是否足够运行嵌入模型")
                    elif settings.EMBEDDING_TYPE == 'openai':
                        check_points.append(f"2. OpenAI服务连接是否正常: {settings.EMBEDDING_API_BASE}")
                        check_points.append(f"3. OpenAI API密钥是否有效")
                        check_points.append(f"4. 模型 '{settings.EMBEDDING_MODEL}' 是否在您的OpenAI账户中可用")
                    
                    error_msg = f"Milvus向量缺失错误: {e}\n" + "请检查:\n" + "\n".join(check_points)
                    raise RuntimeError(error_msg) from e
                else:
                    # 其他错误，直接抛出
                    raise e
        except Exception as e:
            logger.error(f"Failed to add documents to vector store: {e}")
            raise e

    def similarity_search(self, query: str, k: int = 10, search_params: Optional[Dict[str, Any]] = None) -> List[Document]:
        logger.info(f"执行向量检索，查询内容: {query}")
        logger.info(f"向量检索条件详情: query_length={len(query)}, k={k}")
        try:
            # 检查向量存储类型
            vector_store_type = str(type(self.vector_store)).lower()
            
            # 为Milvus特别处理参数
            if "milvus" in vector_store_type:
                # 确保ef值始终大于k值，这是Milvus的要求
                ef_value = max(k * 2, 16, 32)  # 增加最小值到32，确保满足要求
                search_params = {"ef": ef_value}
                logger.info(f"为Milvus设置搜索参数: ef={ef_value}")
                
                # 使用明确的参数传递方式，避免关键字参数冲突
                # 修复：直接传递参数而不是使用search_params关键字
                try:
                    results = self.vector_store.similarity_search(
                        query, 
                        k=k,
                        ef=ef_value  # 直接传递ef参数
                    )
                except Exception as milvus_e:
                    logger.warning(f"使用ef参数直接传递失败: {milvus_e}，尝试使用search_params")
                    # 回退到使用search_params参数
                    results = self.vector_store.similarity_search(
                        query, 
                        k=k,
                        search_params=search_params
                    )
            else:
                results = self.vector_store.similarity_search(query, k=k)
                
            logger.info(f"向量检索完成，找到 {len(results)} 个结果")
            
            # 恢复详细的结果日志输出，但在生产环境中可以考虑减少详细信息
            logger.debug(f"===== 向量检索结果详细信息 ====")
            for i, doc in enumerate(results):
                logger.debug(f"结果 {i+1}:")
                logger.debug(f"  文档内容前500字符: {doc.page_content[:500]}...")
                # 检查并输出所有可能的元数据字段变体
                source_value = doc.metadata.get('source', doc.metadata.get('file_path', 'N/A'))
                filename_value = doc.metadata.get('file_name', (os.path.basename(source_value) if source_value != 'N/A' else 'N/A'))
                filetype_value = doc.metadata.get('file_type', 'N/A')
                
                logger.debug(f"  source: {source_value}")
                logger.debug(f"  filename: {filename_value}")
                logger.debug(f"  filetype: {filetype_value}")
                
                # 显示所有元数据，便于调试
                logger.debug(f"  完整元数据: {doc.metadata}")
            logger.debug(f"==============================")
            
            return results
        except Exception as e:
            logger.error(f"向量检索失败: {e}")
            # 尝试使用默认参数再次搜索，但不传递search_params
            try:
                logger.info("尝试使用默认参数重新搜索（不传递search_params）")
                # 检查是否为Milvus并设置正确的ef参数
                vector_store_type = str(type(self.vector_store)).lower()
                if "milvus" in vector_store_type:
                    ef_value = max(k * 2, 16, 32)  # 确保满足Milvus要求
                    results = self.vector_store.similarity_search(query, k=k, ef=ef_value)
                else:
                    results = self.vector_store.similarity_search(query, k=k)
                return results
            except Exception as retry_e:
                logger.error(f"重试也失败: {retry_e}")
                # 最后的回退方案：返回空列表而不是抛出异常
                return []

    def similarity_search_with_metadata_filter(self, query: str, filter: Dict[str, Any], k: int = 10, search_params: Optional[Dict[str, Any]] = None) -> List[Document]:
        """
        执行带元数据过滤的相似性搜索
        
        Args:
            query: 查询字符串
            filter: 元数据过滤条件, 格式为字典
            k: 返回结果数量
            
        Returns:
            过滤后的相关文档列表
        """
        # 合并日志，减少重复输出
        logger.info(f"执行带元数据过滤的向量检索 - 查询内容: {query}, 查询长度: {len(query)}, k: {k}, 过滤条件: {filter}")
        try:
            # 检查是否有过滤条件
            if filter:
                # 检查底层向量存储类型
                vector_store_type = str(type(self.vector_store)).lower()
                
                # 对于Milvus，使用expr参数代替filter以避免参数重复
                if 'milvus' in vector_store_type:
                    logger.info("使用Milvus向量存储，将使用expr参数进行过滤")
                    
                    # 为Milvus设置搜索参数
                    # 确保ef值始终大于k值，这是Milvus的要求
                    ef_value = max(k * 2, 16, 32)  # 增加最小值到32，确保满足要求
                    logger.info(f"为Milvus设置搜索参数: ef={ef_value}")
                    
                    # 构建Milvus兼容的表达式
                    try:
                        # 尝试使用expr参数（Milvus SDK推荐的方式）
                        # 对于简单的company_name过滤，构建对应的expr表达式
                        if 'company_name' in filter:
                            company_value = filter['company_name']
                            if isinstance(company_value, dict) and '$regex' in company_value:
                                # 处理正则表达式过滤
                                pattern = company_value['$regex']
                                # 使用Milvus支持的like操作符替代contains函数
                                results = self.vector_store.similarity_search(
                                    query, 
                                    k=k,
                                    expr=f"company_name like '%{pattern}%'",
                                    ef=ef_value  # 直接传递ef参数而不是search_params
                                )
                            else:
                                # 处理精确匹配
                                results = self.vector_store.similarity_search(
                                    query, 
                                    k=k,
                                    expr=f"company_name == '{company_value}'",
                                    ef=ef_value  # 直接传递ef参数而不是search_params
                                )
                        else:
                            # 对于其他过滤条件，使用手动过滤方式
                            logger.info("复杂过滤条件，使用手动过滤方式")
                            initial_k = max(k * 10, 50)  # 至少50个结果用于过滤
                            # 确保ef值足够大以满足Milvus要求
                            initial_ef = max(initial_k * 2, 32, ef_value)
                            results = self.vector_store.similarity_search(
                                query, 
                                k=initial_k,
                                ef=initial_ef  # 使用足够大的ef值
                            )
                            results = [doc for doc in results if self._match_metadata_filter(doc.metadata, filter)]
                            results = results[:k]  # 截取需要的数量
                    except Exception as expr_e:
                        logger.warning(f"使用expr参数失败: {expr_e}，回退到手动过滤")
                        # 回退方案：先进行普通搜索再手动过滤
                        initial_k = max(k * 10, 50)  # 至少50个结果用于过滤
                        # 确保ef值足够大以满足Milvus要求
                        initial_ef = max(initial_k * 2, 32, ef_value)
                        all_results = self.vector_store.similarity_search(
                            query, 
                            k=initial_k,
                            ef=initial_ef  # 使用足够大的ef值
                        )
                        results = [doc for doc in all_results if self._match_metadata_filter(doc.metadata, filter)]
                        results = results[:k]  # 截取需要的数量
                else:
                    # 对于其他支持filter参数的向量存储实现，直接使用过滤搜索
                    logger.info("使用向量存储的原生过滤功能")
                    # 构建搜索参数
                    search_kwargs = {"k": k, "filter": filter}
                    
                    results = self.vector_store.similarity_search(query, **search_kwargs)
            else:
                    # 没有过滤条件，直接搜索
                    logger.info("无过滤条件，执行普通向量检索")
                    # 对于Milvus不直接传递search_params参数，避免重复传递
                    results = self.vector_store.similarity_search(query, k=k)
            
            logger.info(f"带元数据过滤的向量检索完成，找到 {len(results)} 个结果")
            
            # 恢复结果摘要日志，但减少重复信息
            logger.debug(f"带元数据过滤的向量检索完成，找到 {len(results)} 个结果")
            
            # 只在调试模式下记录前3个结果的详细信息（如果有）
            if len(results) > 0 and logger.isEnabledFor(10):  # 10是DEBUG级别的数值
                logger.debug(f"===== 向量检索结果摘要 ====")
                for i, doc in enumerate(results[:3]):  # 只记录前3个结果
                    logger.debug(f"结果 {i+1}:")
                    # 如果过滤条件中包含公司名称，检查结果是否包含该公司名称
                    if filter and 'company_name' in filter:
                        # 获取公司名称，处理不同格式的过滤条件
                        if isinstance(filter['company_name'], dict) and '$regex' in filter['company_name']:
                            company_name = filter['company_name']['$regex']
                        else:
                            company_name = filter['company_name']
                        logger.debug(f"  包含公司名称 '{company_name}': {'是' if company_name in doc.page_content else '否'}")
                    logger.debug(f"  文档内容前200字符: {doc.page_content[:200]}...")
                    # 检查并输出主要元数据字段
                    source_value = doc.metadata.get('source', doc.metadata.get('file_path', 'N/A'))
                    filename_value = doc.metadata.get('filename', (os.path.basename(source_value) if source_value != 'N/A' else 'N/A'))
                    
                    logger.debug(f"  source: {source_value}")
                    logger.debug(f"  filename: {filename_value}")
                if len(results) > 3:
                    logger.debug(f"  ... 还有 {len(results) - 3} 个结果省略显示 ...")
                logger.debug(f"=======================")
            
            return results
        except Exception as e:
            logger.error(f"带元数据过滤的向量检索失败: {e}")
            # 出错时回退到手动过滤的搜索
            try:
                logger.info("回退到先搜索后手动过滤的方式")
                # 设置搜索参数
                initial_k = max(k * 10, 50)  # 至少50个结果用于过滤
                all_results = self.vector_store.similarity_search(
                    query, 
                    k=initial_k
                )
                
                # 然后手动过滤结果
                filtered_results = [doc for doc in all_results if self._match_metadata_filter(doc.metadata, filter)]
                logger.debug(f"手动过滤后得到 {len(filtered_results)} 个结果")
                return filtered_results[:k]  # 返回需要的数量
            except Exception as fallback_e:
                logger.error(f"回退搜索也失败了: {fallback_e}")
                # 最后的回退方案：返回空列表而不是抛出异常
                return []

    def company_specific_search(self, company_name: str, query: str, k: int = 4) -> List[Any]:
        """
        针对特定公司的搜索，先尝试基于公司名称的精确过滤，再进行语义搜索
        
        Args:
            company_name: 公司名称
            query: 查询内容
            k: 返回结果数量，限制为4以避免请求过大
            
        Returns:
            相关文档列表
        """
        logger.info(f"执行公司特定检索，公司名称: {company_name}, 查询内容: {query[:100]}...")
        logger.debug(f"检索参数: company_name={company_name}, query_length={len(query)}, k={k}")
        
        # 清理公司名称
        cleaned_company_name = self._clean_company_name(company_name)
        logger.info(f"原始公司名称: {company_name}, 清理后公司名称: {cleaned_company_name}")
        
        if not cleaned_company_name:
            logger.warning("清理后的公司名称为空，回退到常规搜索")
            return self.similarity_search(query, k=k)
        
        # 构建多种过滤条件尝试搜索
        filter_conditions = self._build_company_filter_conditions(cleaned_company_name)
        
        logger.info(f"构建了 {len(filter_conditions)} 种过滤条件: {filter_conditions}")
        
        docs = []
        for i, filter_condition in enumerate(filter_conditions):
            try:
                logger.info(f"尝试第 {i+1} 种过滤条件: {filter_condition}")
                docs = self.similarity_search_with_metadata_filter(query, filter=filter_condition, k=k)
                logger.info(f"第 {i+1} 种过滤条件检索完成，找到 {len(docs)} 个结果")
                if docs:
                    logger.info(f"第 {i+1} 种过滤条件成功找到 {len(docs)} 个结果")
                    # 记录检索到的结果摘要
                    logger.info(f"===== 公司特定检索结果摘要 ====")
                    for j, doc in enumerate(docs):
                        logger.info(f"结果 {j+1}:")
                        logger.info(f"  文档内容前200字符: {doc.page_content[:200]}...")
                        if hasattr(doc, 'metadata'):
                            source_value = doc.metadata.get('source', doc.metadata.get('file_path', 'N/A'))
                            filename_value = doc.metadata.get('filename', (os.path.basename(source_value) if source_value != 'N/A' else 'N/A'))
                            company_value = doc.metadata.get('company_name', 'N/A')
                            logger.info(f"  source: {source_value}")
                            logger.info(f"  filename: {filename_value}")
                            logger.info(f"  company_name: {company_value}")
                    logger.info(f"==============================")
                    break
                else:
                    logger.info(f"第 {i+1} 种过滤条件未找到结果")
            except Exception as e:
                logger.error(f"使用第 {i+1} 种过滤条件搜索时出错: {e}")
                logger.exception(e)  # 记录完整的异常堆栈
                # 如果是Milvus相关的错误，尝试简化过滤条件
                # 检查是否是Milvus参数错误，ef应该大于k的错误
                if "ef" in str(e).lower() and "should be larger than k" in str(e).lower():
                    logger.warning("检测到Milvus参数错误，尝试简化过滤条件")
                    # 特殊处理逻辑：增加ef值并减少k值
                    adjusted_k = max(k // 2, 2)  # 减少k值
                    adjusted_ef = max(adjusted_k * 2, 32)  # 增加ef值
                    logger.info(f"调整参数: k={adjusted_k}, ef={adjusted_ef}")
                    
                    # 使用调整后的参数重新尝试搜索
                    try:
                        docs = self.similarity_search_with_metadata_filter(
                            query, 
                            filter=filter_condition, 
                            k=adjusted_k,
                            search_params={"ef": adjusted_ef}
                        )
                        if docs:
                            logger.info(f"调整参数后成功找到 {len(docs)} 个结果")
                            break
                    except Exception as retry_e:
                        logger.error(f"调整参数后仍然失败: {retry_e}")
                continue
        
        # 如果所有过滤条件都失败了，回退到不带过滤条件的搜索
        if not docs:
            logger.info("所有过滤条件都未能找到结果，回退到不带过滤条件的搜索")
            logger.info(f"回退搜索参数: query={query[:50]}..., k={max(k // 2, 2)}")
            # 使用更保守的参数进行回退搜索
            fallback_k = max(k // 2, 2)
            fallback_ef = max(fallback_k * 2, 32)
            docs = self.similarity_search(query, k=fallback_k)
            
        logger.info(f"公司特定检索完成，返回 {len(docs)} 个结果")
        return docs
    
    def _clean_company_name(self, company_name: str) -> str:
        """
        清理和验证公司名称
        
        Args:
            company_name: 原始公司名称
            
        Returns:
            清理后的公司名称
        """
        if not company_name:
            return ""        
        
        # 首先尝试直接从文本中提取标准公司名称模式（包含完整公司后缀）
        standard_company_pattern = r'([一-龥a-zA-Z0-9（）()\-]+?股份有限公司|[一-龥a-zA-Z0-9（）()\-]+?有限责任公司)'
        standard_match = re.search(standard_company_pattern, company_name)
        if standard_match:
            logger.debug(f"通过标准公司模式提取到公司名称: {standard_match.group(1)}")
            return standard_match.group(1)
        
        # 尝试根据标点符号进行切分，取可能包含公司名称的部分
        # 按照常见的中文标点符号切分句子
        sentences = re.split(r'[，,。.？?！!；;]', company_name)
        
        # 从切分后的句子中找到最可能包含公司名称的部分
        best_candidate = ""
        for sentence in sentences:
            sentence = sentence.strip()
            # 检查是否包含典型的公司后缀
            if re.search(r'(股份有限公司|有限责任公司|公司)$', sentence):
                # 优先选择包含完整公司后缀的句子
                best_candidate = sentence
                break
            elif len(sentence) > len(best_candidate) and len(sentence) >= 4:
                # 如果没有找到标准后缀，选择最长的有效句子
                best_candidate = sentence
        
        # 如果通过标点符号切分找到了候选名称，使用它
        if best_candidate:
            cleaned_name = best_candidate
        else:
            # 否则使用原始名称
            cleaned_name = company_name
        
        # 移除明显不是公司名称的部分
        # 例如："本次发行前"、"进入"这样的短语
        cleaned_name = re.sub(r'^(本次发行前|目前|当前|现在|目前情况是|关于|查询|20\d{2}年|、|为推广|提升|业务|报告期内|进入)\s*', '', cleaned_name)
        
        # 特殊处理常见的公司名称模式
        specific_patterns = [
            # 电梯行业公司
            r'(森赫电梯\S*股份有限公司|森赫电梯)',
            # 光电行业公司
            r'(东莞\S*光电\S*股份有限公司|勤上光电)',
            # 网络科技行业公司（特别是山东海看相关）
            r'(山东海看网络科技有限公司|海看网络科技\S*有限公司)',
            # 添加更多行业的常见公司模式
            r'(\S+?电梯\S+?公司)',
            r'(\S+?科技\S+?公司)',
            r'(\S+?股份有限公司|\S+?有限责任公司)'
        ]
        
        for pattern in specific_patterns:
            specific_company_match = re.search(pattern, cleaned_name)
            if specific_company_match:
                logger.debug(f"通过特定模式 '{pattern}' 提取到公司名称: {specific_company_match.group(1)}")
                return specific_company_match.group(1)
        
        # 确保包含典型的公司后缀
        if not re.search(r'(股份有限公司|有限责任公司|公司)$', cleaned_name):
            # 尝试找到更合理的公司名称部分
            # 查找以"有限公司"、"股份公司"等结尾的部分
            match = re.search(r'(.+?(?:有限公司|股份公司|公司))', cleaned_name)
            if match:
                cleaned_name = match.group(1)
            else:
                # 如果没有找到标准后缀，尝试提取可能的公司名称
                match = re.search(r'(.+?(?:有限|股份|集团|企业|科技|实业|电梯))', cleaned_name)
                if match:
                    cleaned_name = match.group(1)
                    # 如果名称看起来不完整，添加"公司"
                    if not re.search(r'(公司|集团|企业)$', cleaned_name):
                        cleaned_name += "公司"
        
        # 过滤掉太短的名称（少于4个字符）
        if len(cleaned_name) < 4:
            return ""
        
        # 最后清理，移除首尾空格
        cleaned_name = cleaned_name.strip()
        
        logger.info(f"原始公司名称: {company_name}, 清理后公司名称: {cleaned_name}")
        return cleaned_name
    
    def _build_company_filter_conditions(self, cleaned_company_name: str) -> List[Dict[str, Any]]:
        """
        构建多种过滤条件，用于尝试不同的搜索策略
        
        Args:
            cleaned_company_name: 清理后的公司名称
            
        Returns:
            过滤条件列表
        """
        logger.info(f"为公司名称 '{cleaned_company_name}' 构建过滤条件")
        filters = []
        
        # 1. 精确匹配 - 优先使用
        exact_match_filter = {"company_name": cleaned_company_name}
        filters.append(exact_match_filter)
        logger.debug(f"添加精确匹配过滤条件: {exact_match_filter}")
        
        # 2. 部分匹配（包含关系）- 关键词在任意位置
        escaped_name = re.escape(cleaned_company_name)
        partial_match_filter = {"company_name": {"$regex": escaped_name}}
        filters.append(partial_match_filter)
        logger.debug(f"添加部分匹配过滤条件: {partial_match_filter}")
        
        # 3. 简化公司名称匹配（去除"股份有限公司"等后缀）
        simplified_name = re.sub(r'(股份有限公司|有限责任公司|公司)$', '', cleaned_company_name)
        if simplified_name != cleaned_company_name and len(simplified_name) > 2:
            simplified_filter = {"company_name": {"$regex": re.escape(simplified_name)}}
            filters.append(simplified_filter)
            logger.debug(f"添加简化名称匹配过滤条件: {simplified_filter}")
        
        # 4. 对包含多个部分的公司名称，尝试匹配每个部分
        # 按地域关键词拆分
        split_source = simplified_name if simplified_name != cleaned_company_name else cleaned_company_name
        name_parts = re.split(r'[省市县镇乡]', split_source)
        for part in name_parts:
            part = part.strip()
            if len(part) >= 3:  # 至少3个字符才有意义
                part_filter = {"company_name": {"$regex": re.escape(part)}}
                filters.append(part_filter)
                logger.debug(f"添加部分名称匹配过滤条件: {part_filter}")
        
        # 5. 提取核心部分进行匹配（去除标准后缀）
        core_part_match = re.search(r'(.+?)(?:股份有限公司|有限责任公司|公司)$', cleaned_company_name)
        if core_part_match:
            core_part = core_part_match.group(1)
            # 如果核心部分足够长，添加为过滤条件
            if len(core_part) >= 4:
                core_filter = {"company_name": {"$regex": re.escape(core_part)}}
                filters.append(core_filter)
                logger.debug(f"添加核心部分匹配过滤条件: {core_filter}")
        
        # 6. 针对特定行业的关键词提取 - 如电梯行业
        industry_keywords = re.findall(r'(电梯|光电|科技|金融|医药|汽车|能源)', cleaned_company_name)
        for keyword in industry_keywords:
            if len(keyword) >= 2:
                industry_filter = {"company_name": {"$regex": f".*{re.escape(keyword)}.*"}}
                filters.append(industry_filter)
                logger.debug(f"添加行业关键词过滤条件: {industry_filter}")
        
        # 7. 添加更宽松的匹配条件 - 允许名称中间有其他字符
        loose_match_name = re.sub(r'(股份|有限|责任|集团|企业|公司)', '', cleaned_company_name)
        if len(loose_match_name) >= 3:
            loose_filter = {"company_name": {"$regex": f".*{re.escape(loose_match_name)}.*"}}
            filters.append(loose_filter)
            logger.debug(f"添加宽松匹配过滤条件: {loose_filter}")
        
        # 8. 处理包含地域前缀的情况 - 扩展到更多城市
        region_prefixes = ["北京", "上海", "广州", "深圳", "杭州", "南京", "武汉", "成都", "西安", "重庆"]
        for prefix in region_prefixes:
            if prefix in cleaned_company_name:
                # 去除地域前缀的匹配
                name_without_region = re.sub(f'^{prefix}', '', cleaned_company_name)
                if name_without_region and len(name_without_region) >= 4:
                    region_filter = {"company_name": {"$regex": re.escape(name_without_region)}}
                    filters.append(region_filter)
                    logger.debug(f"添加去除地域前缀 '{prefix}' 匹配过滤条件: {region_filter}")
                    break
        
        # 9. 针对文档内容的关键词匹配（更宽松的匹配）
        content_filter = {"page_content": {"$regex": re.escape(cleaned_company_name)}}
        filters.append(content_filter)
        logger.debug(f"添加文档内容匹配过滤条件: {content_filter}")
        
        # 去重过滤条件列表
        unique_filters = []
        seen = set()
        for filter_dict in filters:
            # 将字典转为字符串进行比较
            filter_str = json.dumps(filter_dict, sort_keys=True)
            if filter_str not in seen:
                seen.add(filter_str)
                unique_filters.append(filter_dict)
        
        logger.info(f"总共构建了 {len(unique_filters)} 种过滤条件")
        return unique_filters
    
    def _fallback_search(self, query: str, k: int, company_name: str = None) -> List[Document]:
        """
        回退搜索方法
        
        Args:
            query: 查询内容
            k: 返回结果数量
            company_name: 公司名称（可选）
            
        Returns:
            搜索结果列表
        """
        try:
            # 使用更小的k值避免Milvus错误
            fallback_k = min(k * 2, 10)
            fallback_results = self.similarity_search(query, k=fallback_k)
            
            # 如果提供了公司名称，手动过滤包含公司名称的结果
            if company_name and fallback_results:
                # 清理公司名称用于过滤
                cleaned_company_name = self._clean_company_name(company_name)
                if cleaned_company_name:
                    filtered_fallback = [doc for doc in fallback_results if cleaned_company_name in doc.page_content]
                    if filtered_fallback:
                        return filtered_fallback[:k]
            
            # 如果过滤后没有结果，至少返回一些结果
            return fallback_results[:k] if fallback_results else []
        except Exception as fallback_e:
            logger.error(f"回退搜索也失败: {fallback_e}")
            # 最后的回退方案：返回空结果而不是抛出异常
            return []

    def hybrid_search(self, query: str, k: int = 10, filter: Optional[Dict[str, Any]] = None) -> List[Document]:
        """
        混合检索方法，结合向量检索和关键词检索，优化版本
        :param query: 查询字符串
        :param k: 返回的结果数量
        :param filter: 元数据过滤条件
        :return: 检索结果列表
        """
        logger.info(f"执行混合检索，查询内容: {query}")
        logger.info(f"混合检索条件详情: query_length={len(query)}, k={k}, filter={filter}")
        
        try:
            # 执行向量检索
            if filter:
                vector_results = self.similarity_search_with_metadata_filter(query, filter=filter, k=k*2)  # 获取更多候选结果
            else:
                vector_results = self.similarity_search(query, k=k*2)
            
            logger.info(f"向量检索结果数量: {len(vector_results)}")
            
            # 执行关键词检索
            keyword_results = self.hybrid_search_engine.keyword_search(query, vector_results, k=k*2)
            logger.info(f"关键词检索结果数量: {len(keyword_results)}")
            
            # 混合结果并进行可能的重排序
            combined_results = self.hybrid_search_engine.hybrid_search(
                vector_results, keyword_results, query, k=k
            )
            
            logger.info(f"混合检索完成，返回 {len(combined_results)} 个结果")
            return combined_results
        except Exception as e:
            logger.error(f"混合检索失败: {e}")
            # 失败时回退到基础向量检索
            if filter:
                return self.similarity_search_with_metadata_filter(query, filter=filter, k=k)
            else:
                return self.similarity_search(query, k=k)
                
    def adaptive_search(self, query: str, k: int = 10, filter: Optional[Dict[str, Any]] = None) -> List[Document]:
        """
        自适应检索方法，根据查询特征动态调整检索策略，增强版本
        :param query: 查询字符串
        :param k: 返回的结果数量
        :param filter: 元数据过滤条件
        :return: 检索结果列表
        """
        logger.info(f"执行自适应检索，查询内容: {query}")
        
        try:
            # 使用混合检索引擎的自适应功能
            results = self.hybrid_search_engine.adaptive_search(
                query, self, k=k, filter=filter
            )
            
            logger.info(f"自适应检索完成，返回 {len(results)} 个结果")
            return results
        except Exception as e:
            logger.error(f"自适应检索失败: {e}")
            # 失败时回退到混合检索
            return self.hybrid_search(query, k=k, filter=filter)
            
    def _adjust_search_params(self, query: str, initial_k: int, results: List[Document]) -> Tuple[int, int]:
        """
        自适应调整检索参数
        
        Args:
            query: 查询字符串
            initial_k: 初始k值
            results: 当前检索结果
            
        Returns:
            调整后的(k_value, overlap_value)元组
        """
        # 检查结果数量和质量
        result_count = len(results)
        query_length = len(query)
        
        # 默认调整值
        adjusted_k = initial_k
        
        # 根据查询长度调整k值
        if query_length > 300:
            # 长查询通常需要更多上下文
            adjusted_k = min(initial_k * 2, 20)  # 最多增加到20
            logger.debug(f"长查询({query_length}字符)，调整k值为: {adjusted_k}")
        elif query_length < 50:
            # 短查询通常更具体，可能需要更少但更相关的结果
            adjusted_k = max(initial_k // 2, 2)  # 最少为2
            logger.debug(f"短查询({query_length}字符)，调整k值为: {adjusted_k}")
        
        # 根据结果数量调整
        if result_count < initial_k // 2:
            # 结果太少，增加k值
            adjusted_k = min(initial_k * 2, 25)
            logger.debug(f"结果太少({result_count}个)，调整k值为: {adjusted_k}")
        elif result_count > initial_k * 2:
            # 结果太多，减少k值以提高相关性
            adjusted_k = max(initial_k // 2, 3)
            logger.debug(f"结果太多({result_count}个)，调整k值为: {adjusted_k}")
        
        # 默认overlap值（在实际应用中，你可能需要根据文档类型和内容调整）
        adjusted_overlap = max(int(adjusted_k * 0.15), 20)  # 重叠大小为k的15%，最少20
        
        return adjusted_k, adjusted_overlap

    def _match_metadata_filter(self, metadata: Dict[str, Any], filter: Dict[str, Any]) -> bool:
        """
        检查文档的元数据是否匹配过滤条件
        
        Args:
            metadata: 文档的元数据
            filter: 过滤条件
            
        Returns:
            是否匹配
        """
        # 处理$or条件
        if '$or' in filter:
            for sub_filter in filter['$or']:
                if self._match_metadata_filter(metadata, sub_filter):
                    return True
            return False
        
        # 处理$and条件
        if '$and' in filter:
            for sub_filter in filter['$and']:
                if not self._match_metadata_filter(metadata, sub_filter):
                    return False
            return True
        
        for key, value in filter.items():
            if key in ['$or', '$and']:
                continue
            
            # 特殊处理page_content字段（虽然它不是metadata，但我们允许在filter中使用它）
            if key == 'page_content':
                # 这个字段不在metadata中，而是在文档的page_content属性中
                # 所以这里只是返回True，实际过滤应该在调用方处理
                return True
                
            if key not in metadata:
                # 对于可选字段，允许不存在
                # 如果是company_name这样的关键字段，则要求存在
                if key == 'company_name':
                    logger.debug(f"元数据中缺少company_name字段: {metadata}")
                    return False
                continue
            
            # 支持多种过滤操作
            if isinstance(value, dict):
                # 复杂过滤条件，例如 {'$eq': 'value'}, {'$in': ['value1', 'value2']}
                if '$eq' in value and metadata[key] != value['$eq']:
                    return False
                if '$in' in value and metadata[key] not in value['$in']:
                    return False
                if '$ne' in value and metadata[key] == value['$ne']:
                    return False
                if '$regex' in value:
                    import re
                    pattern = value['$regex']
                    if key == 'page_content':
                        # page_content不在metadata中，需要特殊处理
                        # 这里我们只处理metadata字段的正则匹配
                        continue
                    else:
                        # 对metadata字段进行正则匹配
                        if not re.search(pattern, str(metadata.get(key, ''))):
                            return False
            else:
                # 简单值匹配
                if metadata[key] != value:
                    return False
        
        return True
            